# Copyright 2001-2007 by iNeed,Inc. All Rights Reserved.
#-*- encoding:utf-8 -*-
"""
use cases:

"""
from peer import *

__author__  = "Number Huang<huang.bafeng@iNeed.com>"
__status__  = "developing"
__version__ = "0.1108.31.1"



class UpdateStatusTask(Task):
    """
        update the driver status to the server, it includes the gpsInfo(pos,time)
        and the working status.
        offering:   available to offer service
        processing": unavailable
        NOTE: this is only for test now
    """

    def __init__(self,owner,timeIntervalBySec=2,loopcount=-1):#24 hours
         super(UpdateStatusTask,self).__init__(owner,"UpdateDriverStatus",timeIntervalBySec,loopcount)
         self.owner = owner

    def run(self):
         if self.owner.status != ES_UNLOGGED:
            self.owner.reportStatus()

class Driver(Peer):

    """
    use case 1: login/logout
    use case 2: publish/unpublish service
    use case 3: handle msg from center
    use case 4: interact with the passenger

    """
    def __init__(self,owner):

        self.role= EPR_DRIVER
        self.log = owner.log
        super(Driver,self).__init__(owner)
        self.listenport = driverAddr[1]
        self.notifyRequestMap[CSTR_CA] = self._handleCheckAvailabilityRequest
        self.notifyRequestMap[CSTR_CD] = self._handleConfirmDriverRequest
        self.notifyRequestMap[CSTR_BT] = self._handleBeginTansactionRequest
        self.notifyRequestMap[CSTR_ET] = self._handleEndTansactionRequest
        self.notifyResponseMap[CSTR_UDS]=self.handleUpdateStatusResponse
        self.notifyResponseMap[CSTR_RB]=self.handleNotifyBordingResponse
        self.keepAliveTask=None
       
        self.sessionID = driverFirstSession
       
    def enableUDSTask(self):
        """
        only for test now, because in BS enviroment, the webClient will update it periodically
        """
        if not self.keepAliveTask:
            self.keepAliveTask=UpdateStatusTask(self)
            self.taskEngine.addTask(self.keepAliveTask)
            
    def _handleBeginTansactionRequest(self,session,params):
        self._handleStandbyRequest(CSTR_BT,session,params,BT_UI_TIMEOUT)

    def _handleEndTansactionRequest(self,session,params):
        self._handleStandbyRequest(CSTR_ET,session,params,ET_UI_TIMEOUT)
    
    def _IsExisted(self,pubID):
        for service in self.serviceList:
            if service.pubID==pubID:
                return True
        return False
    
    def _checkConflictCA(self,serviceDict):
        """
        for long term CA, it may conflict with the existed service,
        check it first, if conflicted, automatically respond the cancel
        """
        result = False
        
        if not serviceDict.get("poolingID"):#pooling is regarded non-conflict
            
            if self.serviceList:
                depart = serviceDict["departureTime"]
                dest   = serviceDict["departureTime"] + serviceDict["refTime"]
                for service in self.serviceList:
                    
                    t1 = service.orderDict["departureTime"] #- SHORTTIME_LIMIT
                    t2 = service.orderDict["departureTime"] + service.orderDict["refTime"]#+configall.SHORTTIME_LIMIT
                    if (depart>t1 and depart<t2) or (dest>t1 and dest<t2):
                        self.log.error("the pubID_%d(%d-%d) conflict with %d(%d-%d)"%(service.orderDict["pubID"],t1,t2,serviceDict["pubID"],depart,dest))
                        result = True
        return result
    
    def _handleCheckAvailabilityRequest(self,session,params):
        
        serviceDict  = getServiceByDict(params)
        pubID = serviceDict["pubID"]
        if self._IsExisted(pubID):
            self.log.error("the pubID_%d has been in the servicelist"%pubID)
            return session.sendStandyResponse("NOTIFY",params[3], EN_CANCEL,"repeated service")
        
        if  self._checkConflictCA(serviceDict):
            return session.sendStandyResponse("NOTIFY",params[3], EN_CANCEL,"conflict with existed service")
        
        newService = TaxiService(self,serviceDict,ESE_WF_GUI_CA)
        newService.pubID = pubID
        newService.orderDict = serviceDict
        self.serviceList.append(newService)
        
        poolingGroup = serviceDict.get(CSTR3_POOLINGGROUP)
        if poolingGroup:
            for serviceDict,serviceList in poolingGroup:
                newService = TaxiService(self,serviceDict,ESE_WF_GUI_CA)
                newService.pubID        = serviceDict["pubID"]
                newService.orderDict    = serviceDict
                self.serviceList.append(newService)
        
        reporter = Reporter(None,self._handleRejectCA,extraParam={"pubID":pubID})
        self._handleStandbyRequest(CSTR_CA,session,params,CA_UI_TIMEOUT,reporter)
    
    def _handleRejectCA(self,retCode,retInfo,extraInfo): 
        if retCode!=EN_OK:
            pubID = extraInfo["pubID"] 
            service = self.queryService(pubID)
            if service:
                self.deleteService(None,service)   
    
    def _handleCD(self,pubID):
            service = self.queryService(pubID)
            service.updateStatus(ESE_ORDER_DONE)
            statusDict= {"pubID":pubID}
            
            orderDict = service.orderDict
            poolingID = orderDict.get("poolingID")
            firstNewOrder = True
            if orderDict.has_key(CSTR3_ENABLEPOOLING):
                
                if poolingID:
                    statusDict[EDS_POOLINGID]=poolingID
                    service2 = self.queryService(poolingID)
                    if not service2.poolingProcessor:
                            service2.poolingProcessor = PoolingProcessor(self,poolingID)
                            service2.poolingProcessor.addPooling(service2)
                    
                    firstNewOrder = False#service.orderDict.has_key(CSTR3_POOLINGIDGROUP)#for groupPooling
                    service2.poolingProcessor.addPooling(service)
                    service.poolingProcessor = service2.poolingProcessor
                   
            #statusDict[EDS_REMAINEDSEATS]=configall.MAXPERSON        
            if firstNewOrder:
                statusDict[EDS_DESTLOCATION]     = "(%d,%d,'dest')"%(orderDict['x2'],orderDict['y2'])
                statusDict[EDS_DESTTIME]         = getLocalTime(orderDict['destinationTime'])
              
                if orderDict.has_key(CSTR3_ENABLEPOOLING):
                    statusDict[EDS_POOLINGID]       = service.pubID 
                    statusDict[EDS_REMAINEDSEATS]   = configall.MAXPERSON - orderDict["number"]
                else:
                    statusDict[EDS_REMAINEDSEATS]    = 0
            else:
                #TODO:for pooling order, we need to update (destTime,destGrid) 
                lastService = service.poolingProcessor.getLastService()
                orderDict = lastService.orderDict
                statusDict[EDS_DESTLOCATION]     = "(%d,%d,'poolingDest')"%(orderDict['x2'],orderDict['y2'])
                statusDict[EDS_DESTTIME]         = getLocalTime(orderDict['destinationTime'])
                #if orderDict.has_key(CSTR3_ENABLEPOOLING):
                statusDict[EDS_REMAINEDSEATS]= service.poolingProcessor.getRemainSeats()
                statusDict[EDS_POOLINGID] = poolingID
            
                return statusDict
            
    def _handleConfirmDriverRequest(self,session,params):
        
            serviceDict     = getServiceByDict(params)
            pubID = serviceDict["pubID"]
            service = self.queryService(pubID)
            orderDict = service.orderDict
            statusDict = self._handleCD(pubID)
            param =   params[3] 
            
            try:
                poolingStr = orderDict.get(CSTR3_POOLINGIDGROUP)
                if poolingStr:
                    list1 = poolingStr.split(',')
                    #param += "poolingID: %d\r\n"%pubID
                    for item in list1:
                        pubID = int(item)
                        #self.log.debug("handleCD_%d_begin"%pubID)
                        statusDict = self._handleCD(pubID)
                        #self.log.debug("handleCD_%d_done"%pubID)
                session.sendStandyResponse("NOTIFY",param, EN_OK,retCodeMap[EN_OK])
                self.updateStatus(ESE_ORDER_DONE)
                self.reportStatus(statusDict)
                #self.log.debug("handleCDResponse_%d_done"%pubID)
            except:
                self.log.exception("fail")
                
            
            
    def executeOrder(self,service):
        """
        when executing an service, the status of driver is same as the service's
        """
        if service.status==ESE_ORDER_DONE:
            service.updateStatus(ESE_GOFOR_PICKUP)
        
        if self.status==ESE_GOFOR_PICKUP:
            return
        self.updateStatus(ESE_GOFOR_PICKUP)
        statusDict= {"pubID":service.pubID}
        
        orderDict = service.orderDict
        
        if orderDict.has_key(CSTR3_ENABLEPOOLING):
            
            if service.poolingProcessor:
                service.poolingProcessor.update()
                statusDict[EDS_REMAINEDSEATS]= service.poolingProcessor.getRemainSeats()
                statusDict[EDS_POOLINGID] = service.poolingProcessor.mainID #orderDict["poolingID"]
                #statusDict[EDS_DESTLOCATION]     = "(%d,%d,'dest')"%(orderDict['x2'],orderDict['y2'])
            else:
                statusDict[EDS_REMAINEDSEATS]= configall.MAXPERSON - orderDict["number"]
                statusDict[EDS_POOLINGID] = service.pubID
                
                #statusDict[EDS_DESTLOCATION]     = "(%d,%d,'dest')"%(orderDict['x2'],orderDict['y2'])
        else:
            statusDict[EDS_REMAINEDSEATS] =  0
        
        self.reportStatus(statusDict)
        
                 
    def reportStatus(self,extraParamsDict=None):

        params = self.mainFrom2Head + "Action: updateDriverStatus\r\n" + "status: %d\r\n"%self.status
        if extraParamsDict:
            extraParams = makeFieldFromDict(extraParamsDict)
            params += extraParams
            #if extraParamsDict.has_key("pubID"):self.log.debug(params)
                
        flag = getSpecialFlag(CSTR_UDS)
        
        self._sendRequest(self.mainSession,"NOTIFY",params,None,flag)
    
    def notifyBording(self,peerNum,reporter1=None):
        
        session = self.msgProxy.getSessionByPhone(peerNum)
        if session:#in pressure test,it is possible that the passenger has not sayHello when the driver arrived
            params = "From: %s\r\n"%self.phoneNum + "To: %s\r\n"%peerNum
            params += "Action: %s\r\n"%CSTR_RB + "pubID: %d\r\n"%session.pubID
            reporter = Reporter(reporter1,self.handleNotifyBordingResponse,RB_TIMEOUT)
            #flag = getSpecialFlag(CSTR_RB)
            service = self.queryService(session.pubID)
            service.updateStatus(ESE_WFR_RB)
            self._sendRequest(session,"NOTIFY",params,reporter)
            self.updateStatus(ESE_READY_PICKUP)
            self.reportStatus({"pubID":session.pubID})
    
    def handleNotifyBordingResponse(self,retCode,retInfo,extraInfo=None):
        
        pubID = extraInfo[CSTR2_PUBID]
        self.changeSeriveStatusByResponse(pubID,retCode)
        if retCode==EN_OK:
             self.updateStatus(ESE_TRANSATION_GOING)
             self.reportStatus({"pubID":pubID})
                
    def handleUpdateStatusResponse(self,retCode,retInfo,extraInfo=None):
        pass

    def beginTransaction(self,pubID):
       
        self._transaction(CSTR_BT,pubID)
        self.queryService(pubID).updateStatus(ESE_TRANSATION_GOING)
        self.updateStatus(ESE_TRANSATION_GOING)
        self.reportStatus({"pubID":pubID})
        
    def endTransaction(self,pubID):
        
        self._transaction(CSTR_ET,pubID)
        service = self.queryService(pubID)
        
        poolingOrder = None
        self.updateStatus(ESE_TRANSATION_DONE)
        statusDict= {"pubID":service.pubID}
        if service.poolingProcessor:
            #statusDict[EDS_POOLINGID]   ="yes"
            service.poolingProcessor.deletePooling(service)
            poolingOrder = service.poolingProcessor.getActiveOrder()
        if poolingOrder:
            statusDict[EDS_POOLINGID]  = service.poolingProcessor.mainID
            statusDict[EDS_REMAINEDSEATS] = service.poolingProcessor.getRemainSeats()
        else:
            statusDict[EDS_REMAINEDSEATS] = configall.MAXPERSON
        self.reportStatus(statusDict)     
        self.deleteService(None,service)
        self.updateStatus(ES_IDLE)
                       
    def _transaction(self,name,pubID,extraParams=None): 
       
        params = self.mainFrom2Head 
        params +="Action: %s\r\n"%name
        params +="pubID: %d\r\n"%pubID
        if extraParams:
               params +=  extraParams
        flag = getSpecialFlag(name)
        self._sendRequest(self.mainSession,"NOTIFY",params,None,flag)
        
if __name__=="__main__":

    
     print len([])
 
